package test2constructor;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.objenesis.instantiator.util.UnsafeUtils;


/**
 * @author: mornd
 * @dateTime: 2023/5/17 - 20:58
 * ObjectFactory，ObjectProvider 解决构造器产生的循环依赖 （推荐）
 */
@Slf4j
public class Demo2 {
    public static void main(String[] args) {
        UnsafeUtils.getUnsafe().
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("aaa", AAA.class);
        context.registerBean("bbb", BBB.class);
        context.registerBean("aspect", MyAspect.class);
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());
        context.refresh();
        AAA aaa = context.getBean(AAA.class);
        BBB bbb = context.getBean(BBB.class);
        System.out.println("-------------------------");
        System.out.println(aaa.getClass());
        System.out.println(bbb.getClass());
        AAA object = bbb.aaa.getObject();
        System.out.println(object.getClass());
        object.foo();
    }

    static class AAA {
        public AAA(BBB bbb) {
            log.debug("AAA({})", bbb.getClass().getName());
        }

        public void foo() {
            System.out.println("foo....");
        }
    }

    static class BBB {
        private ObjectProvider<AAA> aaa;

        public BBB(ObjectProvider<AAA> aaa) {

            //AAA object = aaa.getObject();  这里调用还是会发生循环依赖
            log.debug("BBB({})", aaa.getClass().getName());
            this.aaa = aaa;
        }
    }

    @Aspect
    static class MyAspect{

        @Before("execution(* foo())")
        public void before() {
            System.out.println("before....");
        }
    }
}
